﻿using System;
using System.Data.Entity.Database;
using System.Linq;
using System.Transactions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NpCrm.DataAccess.Repositories;

namespace NpCrm.Domain.Tests
{
    [TestClass]
    public class DonationBinRepositoryTests
    {
        private TransactionScope _scope;
        [TestInitialize]
        public void TestSetup()
        {
            DbDatabase.SetInitializer(new DropCreateDatabaseIfModelChanges<NpCrm.DataAccess.Core.NpCrmDataContext>());
            _scope = new TransactionScope(TransactionScopeOption.RequiresNew,
                                          new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted });
        }

        [TestCleanup]
        public void TestTeardown()
        {
            if (_scope != null)
                _scope.Dispose();
        }

        [TestMethod]
        public void CanAdd()
        {
            AddFakeBin();
        }

        [TestMethod]
        public void CanGetById()
        {
            var fakeBin = AddFakeBin();
            using(var binRepo = new DonationBinRepository())
            {
                var persistedBin = binRepo.GetById(fakeBin.DonationBinId);
                Assert.IsNotNull(persistedBin);
                Assert.AreNotSame(fakeBin, persistedBin);
                CompareBins(fakeBin, persistedBin);
            }
        }

        [TestMethod]
        public void CanUpdate()
        {
            var fakeBin = AddFakeBin();
            DonationBin updateBin;
            using (var binRepo = new DonationBinRepository())
            {
                updateBin = binRepo.GetById(fakeBin.DonationBinId);
                updateBin.UpdateUserId = "updater";
                updateBin.UpdateDate = DateTime.Now;
                updateBin.Description = "Corner of 5th and Madison";
                //This assert pulls the lazy-load of Address
                Assert.IsNotNull(updateBin.Location);
                binRepo.Commit();
            }
            using (var binRepo = new DonationBinRepository())
            {
                var updatedBin = binRepo.GetById(updateBin.DonationBinId);
                Assert.IsNotNull(updatedBin);
                Assert.AreNotSame(updateBin, updatedBin);
                CompareBins(updateBin, updatedBin);
            }
        }

        [TestMethod]
        public void CanDelete()
        {
            var fakeBin = AddFakeBin();
            using (var binRepo = new DonationBinRepository())
            {
                var binToDelete = binRepo.GetById(fakeBin.DonationBinId);
                binRepo.Delete(binToDelete);
                binRepo.Commit();
            }
            using (var binRepo = new DonationBinRepository())
            {
                var shouldBeNull = binRepo.GetById(fakeBin.DonationBinId);
                Assert.IsNull(shouldBeNull);
            }
        }

        [TestMethod]
        public void CanGetByDescription()
        {
            var fakeBin = AddFakeBin();
            using (var binRepo = new DonationBinRepository())
            {
                var persistedBin = binRepo.GetByDescription(fakeBin.Description.Substring(0, 10)).FirstOrDefault();
                Assert.IsNotNull(persistedBin);
                Assert.AreNotSame(fakeBin, persistedBin);
                Assert.AreEqual(fakeBin.DonationBinId, persistedBin.DonationBinId);
                CompareBins(fakeBin, persistedBin);
            }
        }

        [TestMethod]
        public void CanFindForLocation()
        {
            var fakeBin = AddFakeBin();
            using (var binRepo = new DonationBinRepository())
            {
                var persistedBin = binRepo.FindForLocation(fakeBin.Location.AddressId).FirstOrDefault();
                Assert.IsNotNull(persistedBin);
                Assert.AreNotSame(fakeBin, persistedBin);
                Assert.AreEqual(fakeBin.DonationBinId, persistedBin.DonationBinId);
                CompareBins(fakeBin, persistedBin);
            }
        }

        public static DonationBin AddFakeBin()
        {
            using (var binRepo = new DonationBinRepository())
            {
                var fakeBin = GetFakeBin();
                binRepo.Add(fakeBin);
                binRepo.Commit();
                Assert.IsTrue(fakeBin.DonationBinId > 0);
                return fakeBin;
            }
        }

        public static DonationBin GetFakeBin()
        {
            var fakeAddress = AddressRepositoryTests.AddFakeAddress();
            return new DonationBin
                       {
                           CreateDate = DateTime.Now,
                           CreateUserId = "ajohnson",
                           Description = "Corner of Lexington and Grand",
                           Location = fakeAddress
                       };
        }

        public static void CompareBins(DonationBin expected, DonationBin actual)
        {
            Assert.AreEqual(expected.CreateUserId, actual.CreateUserId);
            Assert.AreEqual(expected.Description, actual.Description);
            Assert.AreEqual(expected.UpdateUserId, actual.UpdateUserId);
            Assert.AreEqual(expected.Location.AddressId, actual.Location.AddressId);
        }
    }
}
